using Newtonsoft.Json;
using Spine;
using Spine.Unity;
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.InputSystem;

namespace Super
{
	/// <summary>
	/// 通用接口
	/// </summary>
	public static class GlobalUtil
	{
		/// <summary>
		/// 获取对象的信息，用于日志输出等操作
		/// </summary>
		/// <param name="data"></param>
		/// <returns></returns>
		public static string GetObjectInfo(object data)
		{
			if (data == null)
			{
				return null;
			}

			System.Type type = data.GetType();
			StringBuilder res = new StringBuilder();
			if (type.IsClass)
			{
				res.AppendLine(type.FullName);
			}
			var jsonSetting = new JsonSerializerSettings();
			jsonSetting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
			jsonSetting.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
			res.AppendLine(JsonConvert.SerializeObject(data, Formatting.Indented, jsonSetting));

			return res.ToString();
		}

		/// <summary>
		/// 把项目的绝对路径，转换为Assets的相对路径（从Assets开始）
		/// 资源加载都是从Assets开始
		/// </summary>
		/// <param name="path">目录或资源的绝对路径</param>
		/// <returns>Assets的相对路径（从Assets开始</returns>
		public static string GetAssetsRelativePath(string path)
		{
			string relativePath = path.Replace("\\", "/");
			if (!relativePath.StartsWith("Assets"))
			{
				relativePath = relativePath.Replace(Application.dataPath, "Assets");
			}
			return relativePath;
		}

		/// <summary>
		/// 获取资源的绝对路径，System.Path 等系统函数需要绝对路径操作
		/// </summary>
		/// <param name="path">Assets开头的路径</param>
		/// <returns>目录或资源的绝对路径</returns>
		public static string GetAbsolutePath(string path)
		{
			path = path.Replace("\\", "/");
			if (path.StartsWith("Assets"))
			{
				path = Application.dataPath + path.Substring(6);
			}
			return path;
		}

		/// <summary>
		/// 获取根据相对路径获取，数据保存的绝对路径
		/// </summary>
		/// <param name="path"></param>
		/// <returns></returns>
		public static string GetPersistentDataPath(string path)
		{
			if (!path.StartsWith(Application.persistentDataPath))
			{
				path = Application.persistentDataPath + "/" + path;
			}
			return path;
		}

		/// <summary>
		/// 深拷贝，先序列化对象，然后再反序列化即可得到和该对象一样的实例
		/// </summary>
		/// <typeparam name="T">对象类型</typeparam>
		/// <param name="obj">对象实例</param>
		/// <returns></returns>
		public static T DeepCopy<T>(T obj)
		{
			var json = JsonConvert.SerializeObject(obj);
			T newObj = JsonConvert.DeserializeObject<T>(json);
			return newObj;
		}


		/// <summary>
		/// list 列表位置交换
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="list">交换的list</param>
		/// <param name="indexA">交换的索引A</param>
		/// <param name="indexB">交换的索引B</param>
		public static void ListSwap<T>(List<T> list, int indexA, int indexB)
		{
			T temp = list[indexA];
			list[indexA] = list[indexB];
			list[indexB] = temp;
		}

		/// <summary>
		/// 获取列表中的元素，越界则获取最后一位元素
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="list"></param>
		/// <param name="index"></param>
		/// <returns></returns>
		public static T GetListByIndexOrLast<T>(List<T> list, int index)
		{
			return list.Count > index ? list[index] : list[list.Count - 1];
		}

		/// <summary>
		/// 获取区间中随机3维向量
		/// 因为命名空间总是冲突，所以自己写个方法
		/// </summary>
		/// <param name="minPoint"></param>
		/// <param name="maxPoint"></param>
		/// <returns></returns>
		public static Vector3 RandomVector3(Vector3 minPoint, Vector3 maxPoint)
		{
			Vector3 res = Vector3.zero;
			res.x = UnityEngine.Random.Range(minPoint.x, maxPoint.x);
			res.y = UnityEngine.Random.Range(minPoint.y, maxPoint.y);
			res.z = UnityEngine.Random.Range(minPoint.z, maxPoint.z);
			return res;
		}

		/// <summary>
		/// 获取区间中随机2维向量
		/// 因为命名空间总是冲突，所以自己写个方法
		/// </summary>
		/// <param name="minPoint"></param>
		/// <param name="maxPoint"></param>
		/// <returns></returns>
		public static Vector2 RandomVector2(Vector2 minPoint, Vector2 maxPoint)
		{
			Vector2 res = Vector2.zero;
			res.x = UnityEngine.Random.Range(minPoint.x, maxPoint.x);
			res.y = UnityEngine.Random.Range(minPoint.y, maxPoint.y);
			return res;
		}

		/// <summary>
		/// 随机获取某点半径范围内的点
		/// </summary>
		/// <param name="center"></param>
		/// <param name="radius"></param>
		/// <param name="onlyEdge"></param>
		/// <returns></returns>
		public static Vector2 GetRandomPoint2(Vector2 center, float radius, bool onlyEdge)
		{
			float angle = UnityEngine.Random.Range(0, 360);
			float radian = Mathf.Deg2Rad * angle;
			float reallyRadius = onlyEdge ? radius : UnityEngine.Random.Range(0, radius);
			Vector2 offset = new Vector3(reallyRadius * MathF.Cos(radian), reallyRadius * MathF.Cos(radian), 0);
			return center + offset;
		}

		/// <summary>
		/// 随机获取一种颜色
		/// </summary>
		/// <returns></returns>
		public static Color GetRandomColor()
		{
			int index = UnityEngine.Random.Range(0, 100);
			return GetColor(index);
		}

		/// <summary>
		/// 获取一种颜色 
		/// </summary>
		/// <param name="index"></param>
		/// <returns></returns>
		public static Color GetColor(int index)
		{
			if (index < 0)
				return Color.white;

			if (index >= DataHelperUtil.ColorList.Count)
			{
				index = index % DataHelperUtil.ColorList.Count;
			}

			return DataHelperUtil.ColorList[index];
		}

		/// <summary>
		/// 编辑器模式下不可使用
		/// </summary>
		/// <param name="color"></param>
		/// <returns></returns>
		public static Texture2D GetTexture2D(Color color, int width = 1, int height = 1)
		{
			Texture2D texture = new Texture2D(width, height, TextureFormat.ARGB32, false);
			RenderTexture renderTexture = new RenderTexture(width, height, 0);
			Material material = new Material(Shader.Find("FormeWork/ColorTexture"));
			material.SetColor("_Color", color);
			Graphics.Blit(texture, renderTexture, material);
			return RenderTextureToTexture2D(renderTexture);
		}

		/// <summary>
		/// 获取纯色贴图
		/// Color32和Color可以直接互转
		/// </summary>
		/// <param name="color"></param>
		/// <returns></returns>
		public static Texture2D GetSmallTexture2D(Color color)
		{
			Texture2D texture = new Texture2D(1, 1, TextureFormat.ARGB32, false);
			texture.SetPixel(0, 0, color);
			texture.Apply();
			return texture;
		}

		public static Texture2D RenderTextureToTexture2D(RenderTexture renderTexture)
		{
			int width = renderTexture.width;
			int height = renderTexture.height;
			Texture2D texture2D = new Texture2D(width, height, TextureFormat.ARGB32, false);
			RenderTexture.active = renderTexture;
			texture2D.ReadPixels(new Rect(0, 0, width, height), 0, 0);
			texture2D.Apply();
			return texture2D;
		}

		public static Texture2D CloneTexture2D(Texture2D texture)
		{
			Texture2D newTextureByRawData = new Texture2D(texture.width, texture.height, texture.format, false);
			// 对于运行时纹理生成，也可以通过GetRawTextureData直接写入纹理数据，返回一个Unity.Collections.NativeArray
			// 这可以更快，因为它避免了 LoadRawTextureData 会执行的内存复制。
			newTextureByRawData.LoadRawTextureData(texture.GetRawTextureData());
			newTextureByRawData.Apply();
			return newTextureByRawData;
		}

		/// <summary>
		/// 不做平行判断
		/// plane.Raycast
		/// 此函数将 enter 设置为沿着射线，相对于它与平面的相交处的距离。 如果射线与平面平行，则函数返回 false 并将 enter 设置为零。 
		/// 如果射线指向相反方向，则函数返回 false/ 并将 enter 设置为沿着射线的距离（负值）
		/// </summary>
		/// <param name="plane"></param>
		/// <returns></returns>
		public static Vector3 GetMouseInPlanePos(Plane plane)
		{
			Vector2 mousePosition = Mouse.current.position.ReadValue();
			Ray ray = Camera.main.ScreenPointToRay(mousePosition);
			bool result = plane.Raycast(ray, out float enter);
			return ray.GetPoint(enter);
		}

		/// <summary>
		/// 检查是否存在某个程序集
		/// </summary>
		/// <param name="assemblyName"></param>
		/// <returns></returns>
		public static bool CheckAssemblyExistByName(string assemblyName)
		{
			var assemblys = AppDomain.CurrentDomain.GetAssemblies();
			foreach (var assembly in assemblys)
			{
				if (assembly.FullName.Contains(assemblyName))
				{
					return true;
				}
			}

			return false;
		}

		/// <summary>
		/// 将sourceAnimator的参数值赋给targetAnimator
		/// </summary>
		/// <param name="sourceAnimator"></param>
		/// <param name="targetAnimator"></param>
		public static void SetAnimatorParameters(Animator sourceAnimator, Animator targetAnimator)
		{
			// 确保两个Animator都不为空
			if (sourceAnimator == null || targetAnimator == null) return;

			// 获取sourceAnimator中的参数值，并将其赋给targetAnimator
			for (int i = 0; i < sourceAnimator.parameterCount; i++)
			{
				AnimatorControllerParameter parameter = sourceAnimator.GetParameter(i);

				// 根据参数的类型执行相应的赋值操作
				switch (parameter.type)
				{
					case AnimatorControllerParameterType.Float:
						targetAnimator.SetFloat(parameter.name, sourceAnimator.GetFloat(parameter.name));
						break;
					case AnimatorControllerParameterType.Int:
						targetAnimator.SetInteger(parameter.name, sourceAnimator.GetInteger(parameter.name));
						break;
					case AnimatorControllerParameterType.Bool:
						targetAnimator.SetBool(parameter.name, sourceAnimator.GetBool(parameter.name));
						break;
					case AnimatorControllerParameterType.Trigger:
						// Triggers不需要赋值
						break;
				}
			}
		}

		public static void SetSpineRoleColor(SkeletonRenderer SR, Color color)
		{
			Slot[] slots = SR.Skeleton.Slots.Items;

			// 遍历每个插槽，并设置其颜色
			foreach (var slot in slots)
			{
				// 设置插槽的颜色
				slot.SetColor(color);
			}
		}
	}
}

